'''
扫描文档类
1、预处理图片
2、分离表格
3、过滤表格

Create By XiaoChen FU At 2021-05-08
'''

import cv2,random,time,os
from img_util import *

class Scan:
    def __init__(self):
        pass

    def pre_deal_image(self,img_path):
        image = cv2.imread(img_path)
        orim = image.copy()

        gray = cv2.cvtColor(orim, cv2.COLOR_BGR2BGRA)
        '''高斯模糊，20210508修改5X5->9X9 (最大边框未找到)'''
        gray = cv2.GaussianBlur(gray, (9, 9), 0)
        canny_nimage = cv2.Canny(gray, 0, 150)
        # imshow(canny_nimage)

        cnts = cv2.findContours(canny_nimage.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)[1]
        cnts = sorted(cnts, key=cv2.contourArea, reverse=True)[:5]

        screenCnt = None
        screentCntTemp = None
        # 遍历轮廓
        for c in cnts:
            # 计算轮廓近似
            peri = cv2.arcLength(c, True)
            # C表示输入的点集
            # epsilon表示从原始轮廓到近似轮廓的最大距离，它是一个准确度参数
            # True表示封闭的
            approx = cv2.approxPolyDP(c, 0.02 * peri, True)

            # 4个点的时候就拿出来
            if len(approx) == 4:
                print('----4个顶点坐标-----')
                print(order_points(approx.reshape(4, 2)))
                rect_point = order_points(approx.reshape(4, 2))
                print(rect_point[2][0] / rect_point[2][1])
                '''表格长宽比，大于0.5，小于1'''
                whp = (rect_point[2][0] - rect_point[0][0]) / (rect_point[2][1] - rect_point[0][1])
                if whp < 1 and whp > 0.5:
                    if screenCnt is not None:
                        '''如果多个框，则使用最小框（x坐标最大）'''
                        if rect_point[0][0] > screentCntTemp[0][0]:
                            screenCnt = approx
                    else:
                        screenCnt = approx

                    '''保存符合条件的且经过排序的坐标'''
                    screentCntTemp = rect_point

            cv2.drawContours(image, [approx], -1,
                             (random.randint(0, 255), random.randint(100, 255), random.randint(0, 255)), 2)

        print("STEP 2: 获取轮廓")
        cv2.imwrite(r'image/t5_0.png', image)
        cv2.drawContours(image, [screenCnt], -1, (0, 255, 0), 2)
        cv2.imwrite(r'image/t5_1.png', image)

        '''维度转换 => 4x2'''
        screent_cnts = screenCnt.reshape(4, 2)
        # print(screent_cnts)
        # print(screent_cnts[0][0], screent_cnts[0][1], screent_cnts[1][0], screent_cnts[1][1])
        #     screent_cnts = [[(screent_cnts[0][0]-5),(screent_cnts[0][1]-5)],
        #                     [(screent_cnts[1][0]+5),(screent_cnts[1][1]+5)]]

        '''顶点排序'''
        n_screent_cnts = order_points(screent_cnts)

        '''扩大边缘'''
        #     n_screent_cnts = np.zeros((4, 2), dtype=np.int)
        n_screent_cnts[0][0] = n_screent_cnts[0][0] - 15
        n_screent_cnts[0][1] = n_screent_cnts[0][1] - 15
        n_screent_cnts[1][0] = n_screent_cnts[1][0] + 15
        n_screent_cnts[1][1] = n_screent_cnts[1][1] - 15
        n_screent_cnts[2][0] = n_screent_cnts[2][0] + 15
        n_screent_cnts[2][1] = n_screent_cnts[2][1] + 15
        n_screent_cnts[3][0] = n_screent_cnts[3][0] - 15
        n_screent_cnts[3][1] = n_screent_cnts[3][1] + 15
        print(n_screent_cnts)
        #     print(n_screent_cnts[0])
        #     print(n_screent_cnts[1])

        # imshow(image)

        # 透视变换
        warped = four_point_transform(orim, n_screent_cnts)
        cv2.imwrite(r'image/t5_2.png', warped)
        wrapped_orim = warped.copy()

        '''以下处理，无实质作用 -- 2021-05-08'''
        # 二值处理
        warped = cv2.cvtColor(warped, cv2.COLOR_BGR2GRAY)
        ref = cv2.threshold(warped, 120, 255, cv2.THRESH_BINARY)[1]
        cv2.imwrite(r'image/t5_3.png', ref)

        ref = cv2.GaussianBlur(ref, (5, 5), 0)
        canny_nimage = cv2.Canny(ref, 0, 150)
        cv2.imwrite(r'image/t5_4.png', canny_nimage)

        cnts = cv2.findContours(canny_nimage.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)[1]
        #     cv2.drawContours(wrapped_orim, cnts, -1, (0, 255, 0), 2)
        #     imshow(wrapped_orim)
        cnts = sorted(cnts, key=cv2.contourArea, reverse=True)[:5]

        # 遍历轮廓
        for c in cnts:
            # 计算轮廓近似
            peri = cv2.arcLength(c, True)
            # C表示输入的点集
            # epsilon表示从原始轮廓到近似轮廓的最大距离，它是一个准确度参数
            # True表示封闭的
            approx = cv2.approxPolyDP(c, 0.02 * peri, True)

            # 4个点的时候就拿出来
            if len(approx) == 4:
                screenCnt = approx
                break
        print('screentCnt:', screenCnt)
        print('----')
        print(screenCnt.reshape(4, 2))
        raw_wo = wrapped_orim.copy()
        cv2.drawContours(raw_wo, [screenCnt], -1, (0, 255, 0), 2)
        cv2.imwrite(r'image/t5_5.png', raw_wo)
        # cv2.imwrite(r'image/t5_6.png', wrapped_orim)
        return wrapped_orim

    '''
    抽取核心区域
    image_shape:图像
    '''
    def pick_roi(self,image_shape):
        print(image_shape.shape)
        '''缩放图像 (1197x1547)为经验值'''
        image = cv2.resize(image_shape, (1197, 1547))
        gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

        #     element = cv2.getStructuringElement(cv2.MARKER_CROSS,(1,1))
        #     gray = cv2.erode(gray,element)

        element = cv2.getStructuringElement(cv2.MORPH_RECT, (1, 1))
        gray = cv2.erode(gray, element)

        #     gray = cv2.GaussianBlur(gray,(5, 5), 0)

        dst = cv2.Canny(gray, 100, 150, None, 3)  ##image,minVal,MaxVal    3-算子大小
        #     imshow(dst)
        cimage = image.copy()

        '''--检测线条--'''
        ###调整第一波参数： 170，2，12
        rho = 1  # 累加器的距离分辨率
        theta = np.pi / 180  # 弧度
        theshold = 170  # 阈值参数
        minLinLength = 20  # 最小线段长度
        maxLineGap = 12  # 最大间隙
        print(theta)
        linesP = cv2.HoughLinesP(dst, rho, theta, theshold, None, minLinLength, maxLineGap)
        # print(len(linesP))

        horizontal_lines = []  #水平线条集合
        vertical_lines = []    #垂直线条集合
        for i in range(len(linesP)):
            l = linesP[i][0]
            if is_horizontal(l):
                horizontal_lines.append(l)
            if is_vertical(l):
                vertical_lines.append(l)

        horizontal_lines = overlapping_filter(horizontal_lines, 1)
        vertical_lines = overlapping_filter(vertical_lines, 0)
        print('长度大小：%s' % str(len(horizontal_lines)))

        '''保存头部及37个选项文件夹'''
        options_dir_path = r'image/t5_options/' + str(time.time())
        if os.path.exists(options_dir_path) == False:
            os.mkdir(options_dir_path)

        ###开始画横线
        ch, cw, cc = cimage.shape
        pre_line = [0, 0, 0, 0]
        part_head_count = 0
        part_option_hori_start_line = [0, 0, 0, 0]
        '''选项开始线集合'''
        part_option_hori_line = []
        part_option_hori_start_flag = False

        temp_img1 = cimage.copy()
        for i, line in enumerate(horizontal_lines):
            '''临时使用'''
            cv2.line(temp_img1, (line[0], line[1]), (line[2], line[3]), (0, 205, 100), 1, cv2.LINE_AA)
            print('y坐标：', line[1])
            '''第一条线若纵坐标小于20，则为边缘线'''
            if line[1] < 20 or line[3] == 0:
                continue
            if pre_line is None or pre_line[1] == 0:
                pre_line = [0, line[1], cw, line[3]]
                cv2.line(cimage, (0, line[1]), (cw, line[3]), (0, 205, 0), 1, cv2.LINE_AA)
                continue
            print(np.subtract(line[1], pre_line[1]))
            '''
            当前水平线与上一条线的间距
            差值 >= 130 : 头部基本信息内容
            差值 > 40 ：选项
            '''
            if part_head_count == 0 and np.subtract(line[1], pre_line[1]) >= 130:
                #             print(pre_line,np.subtract(line[1],pre_line[1]))
                cv2.line(cimage, (0, line[1]), (cw, line[3]), (255, 0, 0), 1, cv2.LINE_AA)
                part_head_count += 1
                ##截取头部内容，进行识别，号牌号码、车辆类型、使用性质、出厂日期、初次登记日期
                head_image = cimage[pre_line[1] + 5:line[3], pre_line[0] + 2:cw - 5]
                pre_line = [0, line[1], cw, line[3]]
                cv2.imwrite(options_dir_path + '/head.png', head_image)
                part_option_hori_start_line = line
                part_option_hori_start_flag = True
                print('记录part_option_hori_line:', part_option_hori_start_line)
                continue
            if 0 < part_head_count and np.subtract(line[1], pre_line[1]) > 40:
                pre_line = [0, line[1], cw, line[3]]
                '''计算选项横向起始点——start'''
                if part_option_hori_start_flag:
                    print(line[1], part_option_hori_start_line, np.subtract(line[1], part_option_hori_start_line[1]))
                    if np.subtract(line[1], part_option_hori_start_line[1]) > 220:
                        cv2.line(cimage, (0, line[1]), (cw, line[3]), (0, 108, 10), 1, cv2.LINE_AA)
                        part_head_count += 1
                        part_option_hori_line.append(line)
                        part_option_hori_start_flag = False
                        continue
                '''计算选项横向起始点——end'''
                if len(part_option_hori_line) > 0:
                    part_option_hori_line.append(line)

                # cv2.line(cimage, (0, line[1]), (cw, line[3]), (0, 0, 105), 1, cv2.LINE_AA)
                part_head_count += 1
                continue

        cv2.imwrite(r'image/t5_10_temp.png', temp_img1)

        # imshow(cimage)
        #         if part_head_count > 10:
        #             cv2.line(cimage,(0,line[1]),(cw,line[3]),(20,100,0),1,cv2.LINE_AA)
        cimage2 = cimage.copy()
        ###开始画竖线
        pre_line = [0, 0, 0, 0]
        pre_x = 0
        part_res_count = 0
        part_option_verti_line = []
        for i, line in enumerate(vertical_lines):
            print(line)
            line_length = np.absolute(line[3] - line[1])
            print('线段长度：', line_length)

            if line[1] == 0 or line[3] == 0:
                continue
            if pre_line is None or pre_line[1] == 0:
                pre_x = line[0]
                pre_line = [line[0], line[1], line[2], line[3]]
                #选项 垂直区域开始线
                cv2.line(cimage2, (line[0], 0), (line[2], ch), (0, 205, 0), 1, cv2.LINE_AA)
                continue
            ##画垂直线条
            # if line_length > 10:
            #     cv2.line(cimage2, (line[0], 0), (line[2], ch), (0, 50, 200), 1, cv2.LINE_AA)

            print(np.subtract(line[0], pre_line[0]), np.subtract(line[0], pre_x))
            pre_x = line[0]
            if part_res_count == 0 and np.subtract(line[0], pre_line[0]) > 450:
                pre_line = [line[0], line[1], line[0], line[3]]
                # print(pre_line)
                # cv2.line(cimage2, (line[0], 0), (line[2], ch), (100, 0, 50), 10, cv2.LINE_AA)
                part_res_count += 1
                part_option_verti_line.append(line)
                continue
            if part_res_count == 1:
                pre_line = [line[0], line[1], line[0], line[3]]
                # cv2.line(cimage2, (line[0], 0), (line[2], ch), (100, 0, 50), 10, cv2.LINE_AA)
                part_res_count += 1
                part_option_verti_line.append(line)
                continue
            if part_res_count == 2 and np.subtract(line[0], pre_line[0]) > 450:
                pre_line = [line[0], line[1], line[0], line[3]]
                # cv2.line(cimage2, (line[0], 0), (line[2], ch), (100, 0, 50), 10, cv2.LINE_AA)
                part_res_count += 1
                part_option_verti_line.append(line)
                continue
            if part_res_count == 3:
                pre_line = [line[0], line[1], line[0], line[3]]
                # cv2.line(cimage2, (line[0], 0), (line[2], ch), (100, 0, 50), 10, cv2.LINE_AA)
                part_res_count += 1
                part_option_verti_line.append(line)
                continue

        print('-------截取选项-------------')
        options_pos = []
        option_gap = 0
        for i in range(len(part_option_verti_line)):
            if i == 0 or i == 2:
                for j in range(len(part_option_hori_line)):
                    if i < len(part_option_verti_line) - 1 and j < len(part_option_hori_line) - 1:
                        if option_gap > 0:
                            option_gap -= 1
                            continue
                        if len(options_pos) == 0:
                            #                         print([part_option_verti_line[i][0],part_option_hori_line[j][1],part_option_verti_line[i+1][0],part_option_hori_line[j+4][1]])
                            options_pos.append([part_option_verti_line[i][0], part_option_hori_line[j][1],
                                                part_option_verti_line[i + 1][0], part_option_hori_line[j + 4][1]]);
                            option_gap = 3
                        elif len(options_pos) == 3 or len(options_pos) == 4:
                            options_pos.append([part_option_verti_line[i][0], part_option_hori_line[j][1],
                                                part_option_verti_line[i + 1][0], part_option_hori_line[j + 2][1]])
                            option_gap = 1
                        else:
                            options_pos.append([part_option_verti_line[i][0], part_option_hori_line[j][1],
                                                part_option_verti_line[i + 1][0], part_option_hori_line[j + 1][1]])

        print(os.path.exists(options_dir_path))
        print(options_dir_path)
        count = 1
        for option in options_pos:
            cv2.rectangle(cimage2, (option[0], option[1]), (option[2], option[3]), (108, 15, 202), 2)
            option_image = cimage[option[1]:option[3], option[0]:option[2]]
            cv2.imwrite(options_dir_path + '/t5_10_%d.png' % count, option_image)
            count += 1

        print(len(options_pos))
        # imshow(cimage2)

        cv2.imwrite(r'image/t5_10_1.png', cimage2)
        return len(options_pos),options_dir_path